package me.spring.cloud.components.starter.rpc.response.handler;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import me.spring.cloud.common.components.response.annotation.IgnoreGlobalResp;
import me.spring.cloud.common.components.response.service.ResponseService;
import me.spring.cloud.common.components.rpc.response.Response;
import me.spring.cloud.common.components.util.json.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author luffy
 * @description: 全局统一response
 * @date 2019-11-15 14:04
 */
@Slf4j
@Order(1)
@RestControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {

  @Resource
  public ResponseService responseService;

  @Autowired
  private HttpServletRequest httpServletRequest;

  private AntPathMatcher matcher = new AntPathMatcher();

  /**
   * Whether this component supports the given controller method return type and the selected {@code
   * HttpMessageConverter} type.
   * @param returnType the return type
   * @param converterType the selected converter type
   * @return {@code true} if {@link #beforeBodyWrite} should be invoked; {@code false} otherwise
   */
  @Override
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    //判断支持的类型，因为我们定义的CommonResponse 里面的body可能是任何类型，这里就不判断统一放过
    //如果你想对执行的返回体进行操作，可将上方的Object换成你自己的类型
    if (returnType.hasMethodAnnotation(IgnoreGlobalResp.class)) {
      return false;
    }
    return true;
  }

  /**
   * Invoked after an {@code HttpMessageConverter} is selected and just before its write method is invoked.
   * @param body the body to be written
   * @param returnType the return type of the controller method
   * @param selectedContentType the content type selected through content negotiation
   * @param selectedConverterType the converter type selected to write to the response
   * @param request the current request
   * @param response the current response
   * @return the body that was passed in or a modified (possibly new) instance
   */
  @Override
  public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
      Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
      ServerHttpResponse response) {
    if(null != responseService.getIgnoreUrls() && !responseService.getIgnoreUrls().isEmpty() && responseService.getIgnoreUrls().stream()
        .anyMatch(s -> matcher.match(s, httpServletRequest.getRequestURI()))){
      return body;
    }
    if (null != body) {
      log.debug("请求返回数据类型class={}", body.getClass().getName());
    }
    Response result;
    //兼容原来的接口返回
    if (body instanceof Response) {
      result = (Response) body;
    } else {
      result = responseService.success(body);
    }
    //debug时打印响应结果
    if (log.isDebugEnabled()) {
      log.debug("响应数据参数：{} ", result);
    }
    if (body instanceof String) {
      return JsonUtil.toJSON(result);
    }
    return result;
  }
}
